#pragma once
#include <cstdint>
#include <string>
#include <vector>
#include "XnccType.h"

namespace xncc {
namespace user {
    /// 用户注册的回调函数
    /// std::function<void(const char*, uint32_t, thread_id_t, connection_id_t)>
    ///  参数一 数据  参数二 数据长度   参数三   线程id， 参数四 连接的id
    using UserRegFunc = types::UserFunc;
    class EventEngineImpl;
    class EventEngine
    {
      public:
        /**
         * EventEngine
         * 构造引擎类  引擎类将运行在一个线程中 id 要与配置文件的id一致 根据id实现引擎类的功能
         * @param  {types::engine_id_t} id :
         */
        explicit EventEngine(types::engine_id_t engine_id);
        /**
         * ~EventEngine
         *
         */
        virtual ~EventEngine();
        /**
         * EventEngine
         * 引擎类 禁止move
         * @param  {EventEngine&} undefined :
         */
        EventEngine(const EventEngine&&) = delete;
        /**
         * EventEngine
         * 引擎类 禁止copy
         * @param  {EventEngine} undefined :
         */
        EventEngine(const EventEngine&) = delete;

        EventEngine& operator=(const EventEngine&&) = delete;

        EventEngine& operator=(const EventEngine&) = delete;
        /**
         * id
         * @return {types::engine_id_t}  :
         */
        types::engine_id_t id();

        /**
         * 初始化函数里边，一般来说 用户需要在初始化函数中做以下事情
         * 1. 注册回调函数
         * 2. 需要定时器的注册定时器函数
         * 3. 需要自定义队列的调用subQueue
         */
        virtual void init() = 0;
        /**
         *  子类可以继承来处理连接建立， 一般来说可以做的事情:
         *  1. 根据连接id 获取连接信息
         *  2. 根据连接id 管理多连接
         * @param  {types::connection_id_t} undefined 连接的ID:
         * @param  {types::thread_id_t} undefined     连接来自于哪个IPC线程:
         */
        virtual void handleConnected(types::connection_id_t /*unused*/, types::thread_id_t /*unused*/) {}
        /**
         * 子类可以继承来处理连接断开
         * @param  {types::connection_id_t} undefined :
         * @param  {types::thread_id_t} undefined     :
         * @param  {std::string} disconnectedReason  断开的原因 :
         */
        virtual void handleDisconnected(types::connection_id_t /*unused*/,
                                        types::thread_id_t /*unused*/,
                                        const std::string& disconnectedReason)
        {
        }

        /**
         * 主动关闭某个连接
         * @param  {types::connection_id_t} undefined :
         * @param  {types::thread_id_t} undefined     :
         * @return {bool}                             :
         */
        static bool kickConnection(types::connection_id_t, types::thread_id_t);

        /**
         * 获取连接上对应的对端地址
         * @param  {types::connection_id_t} id :
         * @return {std::string}               :
         */
        std::string getPeerAddr(types::connection_id_t conn_id);

        /**
         * 注册回调函数
         * @param  {types::message_id_t} id 消息号 :
         * @param  {UserRegFunc} cb      消息对应的回调函数   :
         */
        void registerUserFunc(types::message_id_t msg_id, const UserRegFunc& user_func);
        /**
         * 定时函数
         * @param  {int64_t} milli      表示定时函数的起始时间点 微秒 unix时间戳  :
         * @param  {int64_t} interval   interval = 0 表示非周期性的 >0 表示周期性的 微秒 :
         * @param  {types::Task} task   要定时执行的任务 :
         * @return {types::timer_id_t}  成功返回 定时器ID 失败返回 INVALID_TIMER_ID:
         */
        types::timer_id_t setTimerFunc(int64_t milli, int64_t interval, const types::Task& task);
        /**
         * 定时函数 从现在开始执行
         * @param  {int64_t} interval   interval = 0 表示非周期性的 >0 表示周期性的 微秒:
         * @param  {types::Task} task   要定时执行的任务:
         * @return {types::timer_id_t}  成功返回 定时器ID 失败返回 INVALID_TIMER_ID:
         */
        types::timer_id_t setIntervalFuncFromNow(int64_t interval, const types::Task& task);
        /**
         * 定时函数 在某个时间点执行
         * @param  {std::string} tpoint 字符串时间 格式是  2021-09-23_18:00:00.123:
         * @param  {types::Task} task   要定时执行的任务:
         * @return {types::timer_id_t}  成功返回 定时器ID 失败返回 INVALID_TIMER_ID:
         */
        types::timer_id_t runAtOnce(const std::string& tpoint, const types::Task& task);
        /**
         * 定时器取消函数
         * @param  {types::timer_id_t} id 要取消的定时器ID:
         */
        void cancelTimer(types::timer_id_t timer_id);
        /**
         * 申请一个数据队列 调用该接口的引擎做为消费者 其他线程可以向该队列发送数据
         * 一般用在使用第三方API的程序中，该引擎需要接收第三方API的数据
         * @param  {types::queue_id_t} queueId     自定义的队列ID:
         * @param  {types::queue_size_t} queueSize 自定义的队列大小:
         * @param  {bool} autoExpand               队列是否自动扩容 不支持自动扩容的队列 发送数据的时候遇到队列满的情况
         * 会阻塞等待直到数据可以被写入:
         * @return {int}                           成功则返回 0 :
         */
        int subQueue(types::queue_id_t queueId, types::queue_size_t queueSize, bool autoExpand = false);

        /**
         * 发送数据 在配置信息conf.json中订阅的引擎可以收到数据
         * 这个发送接口是给其他业务线程发送数据用的 发送和订阅的关系在配置文件中的配置
         * @param  {char*} buf              要发送的数据:
         * @param  {uint32_t} len           要发送的数据长度:
         * @param  {types::message_id_t} id 要发送的消息ID:
         * @return {int}                    成功则返回 0 失败非0:
         */
        int sendData(const char* buf, uint32_t len, types::message_id_t msg_id);
        /**
         * 这个发送函数是发送数据到当前引擎的发布队列，订阅发布队列的引擎将会收到数据
         * @param  {char*} buf                 要发送的数据:
         * @param  {uint32_t} len              要发送的数据长度:
         * @param  {types::message_id_t} id    要发送的消息ID:
         * @param  {types::queue_id_t} queueId 将数据发送给哪个队列, 队列ID是配置文件中的发布ID，可以通过 GetPubIds()
         * 来获取当前引擎有哪几个发布ID 这种情况下 将不会校验消息ID是否应该被发送到该队列中:
         * @return {int}                       成功则返回 0 失败非0:
         */
        int sendAny(const char* buf, uint32_t len, types::message_id_t msg_id, types::queue_id_t queueId);
        /**
         * 当前引擎都配置了那几个发布队列
         *
         * @return {const}  队列的ID集合:
         */
        [[nodiscard]] const std::vector<types::queue_id_t>& GetPubIds() const;
        /**
         * 这个发送函数是专门给通过subQueue 订阅的队列发送数据的函数
         * 不允许多线程发送给同一个队列 否则将出现未定义错误
         * @param  {char*} buf                 要发送的数据:
         * @param  {uint32_t} len              要发送的数据长度:
         * @param  {types::message_id_t} id    要发送的消息ID:
         * @param  {types::queue_id_t} queueId 将数据发送给哪个队列:
         * @return {int}                       成功则返回 0 失败非0:
         */
        static int sendData(const char* buf, uint32_t len, types::message_id_t msg_id, types::queue_id_t queueId);
        /**
         * 这个发送函数是专门给通过subQueue 订阅的队列发送数据的函数
         * 允许多线程发送给同一个队列
         * @param  {char*} buf                 要发送的数据:
         * @param  {uint32_t} len              要发送的数据长度:
         * @param  {types::message_id_t} id    要发送的消息ID:
         * @param  {types::queue_id_t} queueId 将数据发送给哪个队列:
         * @return {int}                       成功则返回 0 失败非0:
         */
        static int
        sendDataWithLock(const char* buf, uint32_t len, types::message_id_t msg_id, types::queue_id_t queueId);
        /**
         * 这个发送接口是业务线程发送消息到IPC线程，
         * @param  {char*} buf                     要发送的数据:
         * @param  {uint32_t} len                  要发送的数据长度:
         * @param  {types::message_id_t} id        要发送的消息ID:
         * @param  {types::thread_id_t} tid        要把数据发送给哪个线程:
         * @param  {types::connection_id_t} connId 要发送的消息对应的连接ID:
         * @return {int}                           成功则返回 0 失败非0:
         */
        int sendData(const char*            buf,
                     uint32_t               len,
                     types::message_id_t    msg_id,
                     types::thread_id_t     tid,
                     types::connection_id_t connId);

      private:
        EventEngineImpl* inUse_;
    };
}  // namespace user
}  // namespace xncc